﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;


namespace Handrise.Mobile.BasicModal.Audio
{
    public class WaveCodec
    {
        private IntPtr hstr = IntPtr.Zero; //用来执行转换的ACM句柄

        byte[] pcm = {  0x01,0x00,0x01,0x00,0x22,0x56,0x00,0x00,0x22,
                        0x56,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0x00};

        byte[] gsm = {  0x31,0x00,0x01,0x00,0x22,0x56,0x00,0x00,0x7e,
                        0x11,0x00,0x00,0x41,0x00,0x00,0x00,0x02,0x00,
                        0x40,0x01};

        private IntPtr GetPCMFormat()
        {
            IntPtr destination = Marshal.AllocHGlobal(pcm.Length);
            Marshal.Copy(pcm, 0, destination, pcm.Length);
            return destination;
        }

        private IntPtr GetGSMFormat()
        {
            IntPtr destination = Marshal.AllocHGlobal(gsm.Length);
            Marshal.Copy(gsm, 0, destination, gsm.Length);
            return destination;
        }

        public bool StartSeq(WaveFormat lpFormat, WaveFormat lpFormatDst)
        {
            EndSeq();

            UInt32 mmr = 0;
            try
            {
                mmr = WaveNative.acmStreamOpen(ref hstr, 0, GetPCMFormat(),
                GetGSMFormat(), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, WaveNative.ACM_STREAMOPENF_NONREALTIME);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            return mmr == 0;
        }

        public void EndSeq()
        {
            if (hstr != IntPtr.Zero)
            {
                WaveNative.acmStreamClose(hstr, 0);
                hstr = IntPtr.Zero;
            }
        }

        public int Compress(byte[] pBuf, byte[] pDstBuf, int nLen)
        {
            WaveNative.ACMSTREAMHEADER shdr = new WaveNative.ACMSTREAMHEADER();
            shdr.cbStruct = Marshal.SizeOf(typeof(WaveNative.ACMSTREAMHEADER));

            GCHandle handle1 = GCHandle.Alloc(pBuf, GCHandleType.Pinned);
            shdr.pbSrc = handle1.AddrOfPinnedObject();//源音频数据区
            shdr.cbSrcLength = nLen;

            GCHandle handle2 = GCHandle.Alloc(pDstBuf, GCHandleType.Pinned);
            shdr.pbDst = handle2.AddrOfPinnedObject();//压缩后音频数据缓冲区
            shdr.cbDstLength = nLen;

            int mmr = WaveNative.acmStreamPrepareHeader(hstr, ref shdr, 0);
            if (mmr != 0)
            {
                return 0;
            }
            
            //用ACM进行压缩
            mmr = WaveNative.acmStreamConvert(hstr, ref shdr, 0);
            if (mmr != 0)
            {
                return 0;
            }
            while ((shdr.fdwStatus & WaveNative.ACMSTREAMHEADER_STATUSF_DONE) == 0) ;
            WaveNative.acmStreamUnprepareHeader(hstr, ref shdr, 0);
            return shdr.cbDstLengthUsed;
        }

    }
}
